﻿using StackExchange.Redis;
using System;
using System.Collections.Generic;
using System.Linq;

namespace InternetSpiderLib.Scenes.UrlQueues
{
    public class RedisUrlQueue : IUrlQueue
    {
        /// <summary>
        /// 历史数据的Key
        /// </summary>
        public string RedisKey { get; set; }

        /// <summary>
        /// 链接字符串
        /// </summary>
        public string RedisConnectString { get; set; }

        public void AddUrl(string url, DateTime dateTime)
        {
            if (string.IsNullOrEmpty(url))
                return;

            if (string.IsNullOrEmpty(RedisConnectString))
                throw new KeyNotFoundException(RedisConnectString);

            using (ConnectionMultiplexer redisClient = ConnectionMultiplexer.Connect(RedisConnectString))
            {
                var databse = redisClient.GetDatabase();
                databse.SortedSetAdd(RedisKey, url, GetTimestamp(dateTime));
            }
        }

        public List<KeyValuePair<string, DateTime>> GetQueueItem()
        {
            if (string.IsNullOrEmpty(RedisConnectString))
                throw new KeyNotFoundException(RedisConnectString);

            using (ConnectionMultiplexer redisClient = ConnectionMultiplexer.Connect(RedisConnectString))
            {
                var databse = redisClient.GetDatabase();

                var list = databse.SortedSetRangeByScoreWithScores(RedisKey, 0, GetTimestamp(DateTime.Now), take: 10);
                return list?.Select(n => new KeyValuePair<string, DateTime>(n.Element, GetDatetime((long)n.Score))).ToList();
            }
        }

        public bool GetUrl(string url, out DateTime dateTime)
        {
            dateTime = DateTime.MinValue;
            if (string.IsNullOrEmpty(url))
                return false;

            if (string.IsNullOrEmpty(RedisConnectString))
                throw new KeyNotFoundException(RedisConnectString);

            using (ConnectionMultiplexer redisClient = ConnectionMultiplexer.Connect(RedisConnectString))
            {
                var databse = redisClient.GetDatabase();

                var score = databse.SortedSetScore(RedisKey, url);

                if (score.HasValue == false)
                    return false;

                dateTime = GetDatetime((long)score.Value);
                return true;
            }
        }

        protected long GetTimestamp(DateTime dateTime)
        {
            return (dateTime.ToUniversalTime().Ticks - 621355968000000000) / 10000000;
        }

        protected DateTime GetDatetime(long timestamp)
        {
            return new DateTime(timestamp * 10000000 + 621355968000000000).ToLocalTime();
        }

        public void RemoveUrl(string url)
        {
            if (string.IsNullOrEmpty(url))
                return;

            if (string.IsNullOrEmpty(RedisConnectString))
                throw new KeyNotFoundException(RedisConnectString);

            using (ConnectionMultiplexer redisClient = ConnectionMultiplexer.Connect(RedisConnectString))
            {
                var databse = redisClient.GetDatabase();

                var score = databse.SortedSetRemove(RedisKey, url);
            }
        }
    }
}
